# -*- coding:utf-8 -*-
from config import *
import json
import hashlib
import sys
from orm import *
import os
import shutil
import commands
from API import config, get_random_str


def backup():
    try:
        info = commands.getoutput('mongodump --host %s:%d -d %s -o %s --gzip'
                                  % (config['mongodb']['host'],
                                     config['mongodb']['port'],
                                     config['mongodb']['db_name'],
                                     config['backup_root']))
        print info
        return return_true(info)
    except Exception as err:
        return return_false(str(err))


def login(**kwargs):
    try:
        userlist = session.query(User).filter_by(**kwargs)
        if userlist.count():
            return return_true(userlist.first().get_dict())
        else:
            return return_false("No such User or Password Error!")
    except Exception as err:
        return return_false(str(err))


def create_user(**kwargs):
    try:
        if session.query(User).filter_by(name=kwargs['name']).count():
            return return_false("The name is already exist!")
        else:
            user = User(**kwargs)
            user.dir_id = create_dir(name=kwargs['name'], parent_id=1)
            session.add(user)
            session.commit()
            return return_true()
    except Exception as err:
        return return_false(str(err))


def create_set(name, user_id, info):
    try:
        user = session.query(User).get(user_id)
        set = Set(name=name, user_id=user_id, info=info, dir_id=create_dir(name, user.dir_id))
        session.add(set)
        session.commit()
        return return_true()
    except Exception as err:
        return return_false(str(err))


def create_dir(name, parent_id):
    os.mkdir(get_all_path(parent_id) + '/' + name)
    dir = Dir(name=name, parent_id=parent_id)
    session.add(dir)
    session.commit()
    return dir.id


def create_per(user_id, set_id, write=False):
    try:
        session.query(Per).filter_by(user_id=user_id, set_id=set_id).delete()
        per = Per(user_id=user_id, set_id=set_id, write=write)
        session.add(per)
        session.commit()
        return return_true()
    except Exception as err:
        return return_false(str(err))


def delete_per(user_id, set_id):
    try:
        session.query(Per).filter_by(user_id=user_id, set_id=set_id).delete()
        session.commit()
        return return_true()
    except Exception as err:
        return return_false(str(err))


def update_user(**kwargs):
    try:
        user_id = kwargs['id']
        query = session.query(User).filter_by(id=user_id)
        kwargs.pop('id')
        if query.count():
            query.update(kwargs)
            session.commit()
            return return_true()
        else:
            return return_false("No such User!")
    except Exception as err:
        return return_false(str(err))


def all_users():
    arr = []
    try:
        for each in session.query(User).all():
            arr.append(each.get_dict())
        return return_true(arr)
    except Exception as err:
        return return_false(str(err))


def all_sets():
    arr = []
    try:
        for each in session.query(Set).all():
            arr.append(each.get_dict())
        return return_true(arr)
    except Exception as err:
        return return_false(str(err))


def get_set(id):
    try:
        set = session.query(Set).get(id)
        arr = []
        KEY = ['name', 'desc', 'size', 'type', 'abs_path']
        # 给每个加添属性
        for each in Fst.filter(set_id=int(id)):
            tmp = {}
            for each_key in KEY:
                tmp[each_key] = each.__dict__[each_key]

            # 对于每一个文件添加目录属性
            dir_arr = []
            flag = 0
            while True:
                try:
                    dir_arr.append(each.__dict__['d' + str(flag)])
                    flag += 1
                except KeyError:
                    break

            tmp['all_dir'] = dir_arr
            arr.append(tmp)

        info = set.get_dict()
        info['tree'] = arr
        return return_true(info)
    except Exception as err:
        return return_false(str(err))


def delete_user(id):
    try:
        user = session.query(User).get(id)
        print get_all_path(user.dir_id)
        shutil.rmtree(get_all_path(user.dir_id))
        session.delete(user)
        session.commit()
        for each in Fst.filter(user_id=int(id)):
            each.delete()
        return return_true()
    except Exception as err:
        return return_false(str(err))


def delete_set(id):
    try:
        set = session.query(Set).get(id)
        shutil.rmtree(get_all_path(set.dir_id))
        session.delete(set)
        session.commit()
        for each in Fst.filter(set_id=int(id)):
            each.delete()
        return return_true()
    except Exception as err:
        return return_false(str(err))


def delete_file(server_path):
    try:
        for each in Fst.filter(abs_path=server_path):
            each.delete()
        return return_true()
    except Exception as err:
        return return_false(str(err))


def commit(set_id):
    try:
        import zipfile
        set = session.query(Set).get(int(set_id))
        set_path = get_all_path(set.dir_id)

        # 解压
        for fpath, dirs, fs in os.walk(set_path):
            for fname in fs:
                filename = os.path.abspath(os.path.join(fpath, fname))
                if os.path.isfile(filename) and os.path.splitext(filename)[1] == '.zip':
                    zfile = zipfile.ZipFile(filename, 'r')
                    zfile.extractall(os.path.dirname(filename))
                    os.remove(filename)

        # 读取文件
        has_file = 0
        fail_arr = []
        # 遍历文件夹
        for fpath, dirs, fs in os.walk(set_path):
            # 遍历此路径下的文件
            for each in fs:
                has_file = 1
                fp = os.path.join(fpath, each)
                all_dir = {}
                # 解路径
                for index, val in enumerate(fpath[len(set_path) + 1:].split('/')):
                    if not val:
                        break
                    else:
                        all_dir['d' + str(index)] = val
                # 存入mongodb
                kwargs = {'set_id': int(set_id),
                          'user_id': set.user_id,
                          'name': os.path.split(fp)[1],
                          'type': os.path.splitext(fp)[1],
                          'desc': 'File',
                          'size': os.path.getsize(fp),
                          'abs_path': fp,
                          'all_dir': all_dir,
                          }
                fst = Fst(**kwargs)
                try:
                    fst.save()
                except KeyError:
                    fail_arr.append(fp[len(set_path):])
                os.remove(fp)

        # 清空缓存
        if not has_file:
            shutil.rmtree(set_path)
            os.mkdir(set_path)
        return return_true(fail_arr)
    except Exception as err:
        return return_false(str(err))


def pull(set_id=None, server_path=None):
    try:
        if not set_id and not server_path:
            return return_false("There is one param here at least!")
        if set_id:
            set = session.query(Set).get(int(set_id))
            if not set:
                return return_false('No such set!')
            for each in Fst.filter(set_id=int(set_id)):
                each.download()
        if server_path:
            tmp = Fst.filter(abs_path=server_path)
            if not tmp:
                return return_false('No such file!')
            for each in Fst.filter(abs_path=server_path):
                each.download()
        return return_true()
    except Exception as err:
        return return_false(str(err))


def run(json_str):
    try:
        func = eval(json_str['command'])  # 组建函数
        try:
            ret = func(**json_str['argv'])  # 组建参数获取结果
        except KeyError:
            ret = func()
    except Exception, reason:
        ret = return_false(reason)
    return ret


def get_file_md5(f):
    m = hashlib.md5()

    while True:
        data = f.read(10240)
        if not data:
            break

        m.update(data)
    return m.hexdigest()


def get_file(server_path, size=False, md5=False, permission=False):
    JSON = {}
    if os.path.isfile(server_path):
        JSON['return'] = True
        FILE_INFO = {}
        if size:
            FILE_INFO['size'] = os.path.getsize(server_path)
        if md5:
            FILE_INFO['md5'] = get_file_md5(file(server_path))
        JSON['file_info'] = FILE_INFO
    else:
        JSON['return'] = False
        JSON['info'] = "No such a file!"
    return JSON


class Command(LineReceiver):
    def dataReceived(self, data):
        LineReceiver.dataReceived(self, data)

    def lineReceived(self, line):
        print self.logPrefix()
        self.sendLine(json.dumps(run(json.loads(line))))
        self.stopProducing()
